#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include <unistd.h>

namespace ns_task_queue
{
    int g_num_default = 10;
    template <class T>
    class ThreadPool
    {
    private:
        void Lock()
        {
            pthread_mutex_lock(&_mtx);
        }

        void UnLock()
        {
            pthread_mutex_unlock(&_mtx);
        }

        bool IsEmpty()
        {
            return _tq.empty();
        }

        void Wait()
        {
            pthread_cond_wait(&_cond, &_mtx);
        }

        void WakeUp()
        {
            pthread_cond_signal(&_cond);
        }

        ThreadPool(int num = g_num_default)
            : _num(g_num_default)
        {
            pthread_mutex_init(&_mtx, nullptr);
            pthread_cond_init(&_cond, nullptr);
        }

        ThreadPool(const ThreadPool<T> &tp) = delete;
        ThreadPool<T> &operator=(const ThreadPool<T> &tp) = delete;

    public:
        static ThreadPool<T> *GetInstance()
        {
            static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
            //对象还没有被创建
            if (ins == nullptr)
            {
                pthread_mutex_lock(&lock);
                if (ins == nullptr)
                {
                    ins = new ThreadPool<T>;
                    ins->InitThreadPool();
                }
                pthread_mutex_unlock(&lock);
            }
            return ins;
        }

        ~ThreadPool()
        {
            pthread_mutex_destroy(&_mtx);
            pthread_cond_destroy(&_cond);
        }

        void PushTask(const T &in)
        {
            Lock();
            _tq.push(in);
            UnLock();
            WakeUp();
        }

        void PopTask(T *out)
        {
            *out = _tq.front();
            _tq.pop();
        }
        //加上static防止this指针，Rountine只有一个参数
        static void *Rountine(void *args)
        {
            pthread_detach(pthread_self());
            ThreadPool<T> *tq = (ThreadPool<T> *)args;

            while (true)
            {
                // std::cout << "thread running... 线程是：" << pthread_self() << std::endl;
                T t;
                tq->Lock();
                while (tq->IsEmpty())
                {
                    tq->Wait();
                }
                tq->PopTask(&t);
                tq->UnLock();
                t();
            }
        }

        void InitThreadPool()
        {
            pthread_t tid[_num];
            for (int i = 0; i < _num; ++i)
            {
                pthread_create(tid + 1, nullptr, Rountine, this);
            }
        }

    private:
        int _num;          //线程数目
        std::queue<T> _tq; //任务队列,临界资源
        pthread_mutex_t _mtx;
        pthread_cond_t _cond;
        static ThreadPool<T> *ins;
    };
    template <class T>
    ThreadPool<T> *ThreadPool<T>::ins = nullptr;

}